﻿/**
 *    Copyright 2012 Yohan Courbe
 *
 *  Licensed under the Apache License, Version 2.0 (the "License 
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *  
 *      http://www.apache.org/licenses/LICENSE-2.0
 *      
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

using System;
using System.Collections.Generic;
using System.Linq;
using System.Timers;
using NetworkAnalyzer.SQL;
using PacketDotNet;

namespace NetworkAnalyzer.Engines.Sonification
{
    class SonifictionEngine : Engine
    {
        private List<SonificationPacket> _packets = new List<SonificationPacket>();
        private readonly Timer _updateBandwidthTimer;
        private readonly Timer _flushInDatabaseTimer;
        private int _totalPacketSize;
        private readonly object _lock = new object();
        private readonly MysqlDatabaseConnection _dbConnect;

        public SonifictionEngine()
        {
            Name = "Sonifiction";

            _updateBandwidthTimer = new Timer { Interval = 1000, AutoReset = true };
            _updateBandwidthTimer.Elapsed += UpdateBandwidth;
            _updateBandwidthTimer.Start();

            _flushInDatabaseTimer = new Timer {Interval = 10000, AutoReset = true };
            _flushInDatabaseTimer.Elapsed += FlushInDatabaseTimerOnElapsed;
            _flushInDatabaseTimer.Start();

            _dbConnect = MysqlDatabaseConnection.OpenConnection();
        }

        private void FlushInDatabaseTimerOnElapsed(object sender, ElapsedEventArgs elapsedEventArgs)
        {
            List<SonificationPacket> sonificationPackets;

            lock (_lock)
            {
                sonificationPackets = new List<SonificationPacket>(_packets);
                _packets.Clear();
            }

            foreach (var packet in sonificationPackets.Where(packet => packet.Bandwidth != 0))
            {
                MidiMapping.SendSonificationPacket(packet);
            }

            //_dbConnect.Query("START TRANSACTION;");

            //foreach (var packet in sonificationPackets.Where(packet => packet.TotalBandwidthRadarMode != 0))
            //{
            //    _dbConnect.Query(
            //        string.Format(
            //            "INSERT INTO `nac`.`sonnification_packets` " +
            //            "   (`catched_at`, " +
            //            "   `ip_destination`, " +
            //            "   `packet_length`, " +
            //            "   `data`, " +
            //            "   `ip_protocol`, " +
            //            "   `applicative_protocol`, " +
            //            "   `checksum`," +
            //            "   `bandwidth`," +
            //            "   `ttl`) " +
            //            "VALUES (" +
            //            "   '{0}', '{1}', '{2}', '{3}', '{4}', '{5}', '{6}', '{7}', '{8}'" +
            //            ");", 
            //            packet.DateTime.GetMySqlFormattedDate(),
            //            packet.IpDestinationAddress,
            //            packet.Length,
            //            packet.Data.MySqlEscape(),
            //            packet.IpProtocol,
            //            packet.ApplicativeProtocol,
            //            packet.Checksum,
            //            packet.TotalBandwidthRadarMode,
            //            packet.Ttl
            //        )
            //    );
            //}

            //_dbConnect.Query("COMMIT;");
        }

        private void UpdateBandwidth(object sender, ElapsedEventArgs elapsedEventArgs)
        {
            lock (_lock)
            {
                foreach (var sonificationPacket in _packets)
                {
                    sonificationPacket.Bandwidth = _totalPacketSize;
                }

                _totalPacketSize = 0;
            }
        }

        public override void Start()
        {
            
        }

        public override void Stop()
        {
            
        }

        public override void AddPacket(Packet packet)
        {
        
        }

        public override void AddIpTcpPacket(Packet packet, IpPacket ipPacket, TcpPacket tcpPacket)
        {
            SonificationPacket sonificationPacket;
            if (Tools.IsLocalHost(ipPacket.SourceAddress))
            {
                lock (_lock)
                {
                    sonificationPacket = new SonificationPacket(ipPacket.TimeToLive, ipPacket.DestinationAddress, packet.Bytes.Length, tcpPacket.PayloadData, ipPacket.Protocol, Tools.GetApplicativeProtocol(tcpPacket.DestinationPort), tcpPacket.Checksum);
                    Add(sonificationPacket);
                }
            }
            else if (Tools.IsLocalHost(ipPacket.DestinationAddress))
            {
                lock (_lock)
                {
                    sonificationPacket = new SonificationPacket(ipPacket.TimeToLive, ipPacket.SourceAddress, packet.Bytes.Length, tcpPacket.PayloadData, ipPacket.Protocol, Tools.GetApplicativeProtocol(tcpPacket.SourcePort), tcpPacket.Checksum);
                    Add(sonificationPacket);
                }
            }
        }

        public override void AddIpUdpPacket(Packet packet, IpPacket ipPacket, UdpPacket udpPacket)
        {
            SonificationPacket sonificationPacket;
            if (Tools.IsLocalHost(ipPacket.SourceAddress))
            {
                lock (_lock)
                {
                    sonificationPacket = new SonificationPacket(ipPacket.TimeToLive, ipPacket.DestinationAddress, packet.Bytes.Length, udpPacket.PayloadData, ipPacket.Protocol, Tools.GetApplicativeProtocol(udpPacket.DestinationPort), udpPacket.Checksum);
                    Add(sonificationPacket);
                }
            }
            else if (Tools.IsLocalHost(ipPacket.DestinationAddress))
            {
                lock (_lock)
                {
                    sonificationPacket = new SonificationPacket(ipPacket.TimeToLive, ipPacket.SourceAddress, packet.Bytes.Length, udpPacket.PayloadData, ipPacket.Protocol, Tools.GetApplicativeProtocol(udpPacket.SourcePort), udpPacket.Checksum);
                    Add(sonificationPacket);
                }
            }
        }

        private void Add(SonificationPacket sonificationPacket)
        {
            _packets.Add(sonificationPacket);
            _totalPacketSize += sonificationPacket.Length;
        }
    }
}
